Code cleanup, Refactor, and consistency fixes#52
Merged
Conversation
The force-install OCI artifact snapshotted libavcodec-freeworld, gstreamer1-plugins-bad-freeworld, mesa-*-freeworld, and vvenc-libs on a schedule independent of the main image. Those RPMs link against versioned x265/vvenc symbols (e.g. x265_api_get_215, libvvenc.so.1.13) that no longer exist on the rolling Bazzite base, producing runtime errors when ffmpeg or GStreamer try to load them. Install the freeworld codec stack atomically in 02-build.sh via a narrowly-scoped dnf swap allowlist instead — versions co-resolve against the live repos, so ABI skew is impossible by construction. Adds a codec-integrity stage to 08-validate.sh (ldd + ffmpeg -encoders + gst-inspect) that turns this class of failure into a build-time hard fail instead of a runtime one. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Three issues exposed by the first testing build:
1. gstreamer1-plugins-bad-{free,freeworld} are NOT exclusive — bad-free
ships libgstva.so (the VAAPI plugin); freeworld only adds x265enc,
de265, and rtmp on top. The swap was silently removing the va plugin,
breaking GStreamer HW codec acceleration. Switch to an additive install.
2. The Tier 1/2/3 encoder regex required five literal dots in the
capability field, but real ffmpeg output is "V....D" (four dots + D
for direct-rendering support). Every encoder check was a false
negative. Use "[.A-Z]{5}" to match any capability flag combination.
3. libavcodec-freeworld is a parallel-library package useful only when
the system runs Fedora's ffmpeg-free. Bazzite ships RPMFusion's full
ffmpeg which bundles patent codecs in its own libavcodec, so the
freeworld variant is uninstallable (file conflict) and unnecessary.
Drop it from CRITICAL_PACKAGES/VERSIONLOCK_PACKAGES; the swap stays
as a best-effort no-op for non-Bazzite bases.
Also: stop suppressing dnf stderr in the codec section — failures now
log dnf's error message inline for diagnostics.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Second testing build surfaced two new failure modes: 1. F44 RPMFusion's i686 builds of libavcodec-freeworld (8.0.1-6) and gstreamer1-plugins-bad-freeworld (1.28.1-3) are stale — they require libx265.so.215 which the current x265 no longer provides (now .216). The x86_64 builds are fresh and link correctly. Bazzite pulls i686 by default for Steam multilib, so a bare install pulls both arches and aborts on the stale i686. Pin both to .x86_64 — no 32-bit userland needs patent codec libraries. 2. vvenc-libs is a transitive dep of ffmpeg and was already installed by the time we reached the explicit `dnf install vvenc vvenc-libs svt-av1-libs` line. dnf5 aborts the entire transaction with "Failed to resolve" when any requested package is a no-op, even if others would install successfully. Pre-filter against `rpm -q` so we only ask dnf for packages it can actually install. The dnf_codec_swap function now accepts an optional arch suffix that only applies to its direct-install fallback path; the swap path itself remains arch-agnostic since it inherits whatever arches the source had. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
00-kernel.sh: remove `dnf5 versionlock add kernel-cachyos-lto` — no-op on ostree (already documented in 02-build.sh). 07-config.sh: drop the global `set +eu` flip-without-restore; switch the two `((counter++))` increments to arithmetic assign so the script keeps `set -euo pipefail` end-to-end. Also drops the unused "hide incompatible Bazzite recipes" section. 08-validate.sh: remove the broken "Experimential" ldconfig stanza (truncated path, `ldconfig -i` misuse), plus the GDK pixbuf / GLib schemas / font registration / x265enc checks that overlapped with 02-build.sh's own validation. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Delete build_files/wine-installer.sh (~280 lines, no caller in the
Containerfile RUN chain or anywhere else in the repo).
- Drop counter_init / counter_increment from 95-utility-functions.sh
(no call sites). counter_display is retained for 02-build.sh:280.
- Replace README.md with a merge of the option-a + option-c drafts,
dropping the CachyOS kernel and freeworld Mesa feature copy and the
stale Build Architecture script tree. Removes README-option-{a,b,c}.md.
- Delete docs/claude.md (legacy AI-context doc; CLAUDE.md + .claude/
skills/ now cover this role) and drop its README link.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- 00-kernel.sh: shebang `/bin/bash` → `/usr/bin/bash`, quote $pkg in the rpm-erase loop (shellcheck SC2086). - 06-fix-opt.sh: replace raw `echo` status lines with `log_info` per the shell-conventions skill. - 07-config.sh: collapse the five-line `echo` summary block to a single `log_success` (the log_section banners above already trace what ran). - Justfile: `Virtal` → `Virtual` in the ten `[group(...)]` labels. - docs/developer.md: drop the wine-installer.sh entry from the directory layout to match the deletion in the prior commit. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
build_files/02-build.sh + build_files/manifests/*.list Package lists move out of the script into eight declarative `.list` manifests (fedora, fedora-multimedia, rpmfusion, terra, brave, critical, remove, plus a `coprs.list`). 02-build.sh now reads them via `read_manifest`, captures dnf output to a log file (`dnf_log_tail` on failure), and authenticates GitHub API calls through a BuildKit secret mount via the new `github_api_get` helper. The standalone `--allowerasing` guard wrappers were consolidated into 95-utility-functions.sh (prior commit). .github/workflows/build.yml Drop `system_files/**` from `paths-ignore` — those files are COPY'd into the image, so ignoring them silently shipped stale configs until the next scheduled rebuild. Also mounts `GITHUB_TOKEN` as a buildah `--secret` so build scripts can hit the GitHub API without sharing the anonymous runner-pool rate limit. Secret file is created with mode 0600 and removed post-build. system_files/etc/sudoers.d/99-distinction-wheel-nopasswd Replace blanket `%wheel NOPASSWD: ALL` with a scoped policy: passwordless for the atomic-system commands used daily (`rpm-ostree`, `bootc`, `ostree`, `systemctl`, `flatpak`), plus a 60-minute credential cache for everything else. Old Option-A behaviour preserved in comments for easy revert. CLAUDE.md Project-level Claude Code context: working agreement, commands, hard rules (no `--allowerasing`, manifests are the source of truth for package data, `dnf versionlock add` is a no-op on ostree and must not return). .claude/skills/ Three skill files loaded automatically by Claude Code: `build-pipeline` (Containerfile order, mount gotchas, manifest layout), `shell-conventions` (logging library, error-handling policy per script), `keep-it-simple` (minimal-diff guardrails). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- distinction-functions.sh: the CYAN constant was \033[031m, which is red, not cyan. Switch to \033[36m so the variable name matches what the terminal renders (used in the rm-confirm prompt and the `naut` helper). - 05-remote-grabber.sh: shebang `/bin/bash` → `/usr/bin/bash`, the last hold-out among build_files/*.sh. - Rename .github/workflows/clean-images.yaml → .yml so all workflow files share one extension. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
build-cache.yml and build-force-install.yml were ~95% identical: same checkout/login, same skopeo inspect, same version-diff decision logic, same buildx push. Move the shared body into a new _build-oci-artifact.yml that exposes `image`, `builder_dir`, `version_check_tag`, `max_age_days`, and `force_rebuild` as workflow_call inputs. The callers shrink to ~30 lines apiece — they keep their own cron, workflow_dispatch, and workflow_call triggers (preserving any external cross-repo callers), set permissions, and forward inputs to the reusable workflow with `secrets: inherit`. Other changes folded in: - Action versions in the reusable workflow are SHA-pinned with `# vN` annotations, matching build.yml's hardening style (build-cache / build-force-install previously used floating `@v6` / `@v4` / `@v7` tags, so dependabot can now pin minor bumps the same way it does for build.yml). - Documented the 15-day cadence on build-cache.yml: build.yml and build-force-install.yml run every 10 days; cache runs every 15 because its upstream sources rarely change, and the workflow's own inspect→decide step is the real freshness gate (cron is just the heartbeat). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- build-disk.yml: switch BIB_IMAGE from the lorbuschris fork pin (`:20250608`) back to upstream `quay.io/centos-bootc/bootc-image-builder:latest`. osbuild#954 — the reason for the fork — merged 2025-06-13. - distinction-functions.sh `mkcd()`: collapse the three-branch case "$SHELL_TYPE" to a single printf. SHELL_TYPE was never set anywhere, so the zsh and bash branches were unreachable; the printf fallback produces the same output and works in either shell. (Not addressed here: the file still uses zsh-only `read -q` in rm() while declaring `#!/bin/sh` — separate sweep.) - distinctionos-steam-linker.service: replace the placeholder `Documentation=https://github.com/yourusername/DistinctionOS` with the real repo URL. - Nautilus: delete the 320-line org.gnome.Nautilus.desktop override (mostly a stale translation snapshot drifting against upstream) and move the single real customisation — `Name=Files` → `Name=Nautilus` in the C locale — into 07-config.sh as a sed step, mirroring the existing Cider / Winetricks patches. Localised Name[xx]= entries are deliberately left alone, matching the prior override. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The file is sourced from /etc/profile (bash login) and /etc/zsh/zshrc (every zsh interactive shell), so it has to work in both. The shebang claimed `#!/bin/sh` but the body has always used `[[ ]]`, `local`, `=~`, and `disown` — none POSIX. The actual runtime break was rm(): it used zsh-only `read -q "REPLY?"` to read a single keystroke into REPLY. Under bash, `read -q` is not a real flag, so the prompt-and-confirm path errored out. - Shebang: `/bin/sh ` (trailing space) → `/usr/bin/bash`. Adds a header comment naming the two sourcing paths and noting the bash/zsh tolerance is intentional. - rm(): switch to plain `read -r REPLY` (press Enter). Loses the single-keystroke convenience zsh got from `read -q`, but the rest of the confirm logic (`[[ "$REPLY" =~ ^[Yy]$ ]]`) keeps the same semantics and now works in both shells. Drops the now-unneeded trailing `echo` since the user already pressed Enter. Verified by sourcing the file under `bash -c` and `zsh -c`, listing the five defined functions, and running rm() on a fixture directory with both `n` (kept) and `y` (deleted) input. shellcheck -S error clean. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
phantomcortex
marked this pull request as ready for review
June 10, 2026 22:16
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.